<?php
/***************************************************************
*  Copyright notice
*
*  (c) 2010 Kasper Skårhøj <kaska@llab.dtu.dk>
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

class tx_enoteserver_utils {

		// Customize using $TYPO3_CONF_VARS['EXTCONF']['enoteserver']['enoteFolderRelativeToSitePath']
	var $dataDir = 'fileadmin/enoteserver/';	// Relative to site path. Everything goes on inside here!!

		// Configure using $TYPO3_CONF_VARS['EXTCONF']['enoteserver']['showURL']
	var $showUrl = 'http://www.someurl.com/?tx_enoteserver_pi1[show]=';	# Example: 'http://myUrl.com/enoteserver/index.php?id=[pagenumber]&tx_enoteserver_pi1[show]=';

		// These paths can be configured using $TYPO3_CONF_VARS['EXTCONF']['enoteserver']['execCfg'] in localconf.php
	var $execCfg = array (
		'pdflatex' => '/usr/bin/pdflatex -halt-on-error --shell-escape',
		'makeindex' => 'makeindex',
		'zip' => 'zip',
		'rsync' => 'rsync',
		'tidy' => 'tidy',
		'svn' => 'svn',
		'git' => 'git',
		'latexml' => 'PERL5LIB=/home/www-data/prefix/share/perl/5.10.1/ /usr/bin/latexml',
		'latexmlpost' => 'PERL5LIB=/home/www-data/prefix/share/perl/5.10.1/ /usr/bin/latexmlpost',

		'pdflatex_PRECMD' => '',
		'latexml_PRECMD' => '',
		'svnUSERPASSoptions' => '', // Example: --username myusername --password mypassword
	);


	
		// Internal:
	var $encodingMap = array(
			0 => 'utf8',
			1 => 'latin1'
		);
	var $headerLevels = array(
			'chapter' => 0,
			'section' => 1,
			'subsection' => 2
		);
		
		// Same list of box environments as in the preambles:
		// The stylesheet "enoteHTML.css" must reflect configurations of the class boxenv-keys($LaTeX_boxEnvironments)
		// Configured through flexform in the book-record
	var $LaTeX_boxEnvironments = array();
	var $LaTeX_divCmdEnvironments = array();

		// Same list of notice environments as in the preambles:
		// The stylesheet "enoteHTML.css" must reflect configurations of the class noticeenv-keys($LaTeX_noticeEnrironments)
		// Configured through flexform in the book-record
	var $LaTeX_noticeEnrironments = array();

	var $bookConfiguration;	// Set when book-configuration is loaded
	var $bookdir;	// Set when book-configuration is loaded : The directory within $dataDir/books/ where common files for the book is located
	var $bookEncoding;	// Encoding for book (see encodingMap)
	var $enoteHTMLpath = "";	// Usually set to "fileadmin/enoteserver/preview/_HTML/" in constructor

	var $piObj;		// Set to piObj when used from the frontend engine. This can be used to see if the script is used in FE or BE context. Also used for choosing method by which to select records.
	
	


	
		// Constructor:
	function tx_enoteserver_utils()	{
		if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['execCfg']))	{
			$this->execCfg = t3lib_div::array_merge($this->execCfg,$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['execCfg']);
		}
		if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['showURL']))	{	
			$this->showUrl = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['showURL'];
		}
		if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['enoteFolderRelativeToSitePath']))	{	
			$this->dataDir = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['enoteserver']['enoteFolderRelativeToSitePath'];
		}
		$this->setPreviewMode(true);
	}
	
	function setPreviewMode($previewMode) {
		$this->enoteHTMLpath = $this->dataDir.($previewMode ? 'preview' : 'live')."/_HTML/";
	}



	/****************************************
	 ***
	 *** TEX + PDF processing
	 ***
	 ***************************************/

	/**
	 * Generates the PDF file in the SVN folder for the enote UID
	 * Only in Preview mode
	 *
	 * @param	integer		Enote uid
	 * @return 	array		Log array
	 */
	function generateDefaultPDFforEnote($uid)	{
		$record = $this->getEnoteRecord($uid);
		$log = array();
		if (is_array($record))	{
			$dirInfo = $this->getAbsDirFile($record,TRUE);
			if (is_array($dirInfo))	{
				
					# Generate PDF:
				$cmd = $this->execCfg['pdflatex_PRECMD'] ? $this->execCfg['pdflatex_PRECMD'].chr(10) : '';
				$cmd.= 'cd "'.$dirInfo['absDir'].'"'.chr(10);
					# TODO: Do check that we are in this folder...?
				$cmd.= $this->execCfg['makeindex']." \"./".preg_replace('/\.tex$/','.idx',$dirInfo['relFile']).'" 2>&1'.chr(10);
		     	$cmd.= $this->execCfg['pdflatex']." \"./".$dirInfo['relFile'].'"';
					# Render twice!! (for TOC etc):
				exec($cmd,$res,$rescode);
				if (!$rescode) {
					exec($cmd,$res);
				}
				$log['lastLog']['PDFLaTeX'] = $res;
				$log['returnCode'] = $rescode;
			}
		}
		
		return $log;
	}

	/**
	 * Creates a composite PDF of multiple enotes using common resources (all ../ references to tex and image files) from books/ folder.
	 * 
	 * @param	array		Array of enote uids to combine. Assuming that all eNotes are of the same book! This must be checked before calling function!
	 * @param	string		Preamble file, relative to ../ directory of the main tex file. Not used in HTML mode.
	 * @param	string		Postamble file, relative to ../ directory of the main tex file. Not used in HTML mode.
	 * @param	string		The mode: "HTML", "composite" (PDF)
	 * @param	array		The box-environments to include (keys). Not used in HTML mode.
	 * @param	boolean		If set, preview mode. Else "live" mode.
	 * @param	string		The tex-filename created in temp/ folder. If not given, a random name is formed.
	 * @return 	array		Log array
	 */
	function createCompositePDF($eNotes,$field_preamble,$field_postamble,$mode,$boxEnv,$previewMode,$fileName='',$allowCached=false,$title="eNote collection")	{
		// First, load directory and book information on notes:
		$notes = array();
		$firstIteration = TRUE;
		foreach($eNotes as $uid)	{
			$eNoteRec = $this->getEnoteRecord($uid);
			$eNoteRecs[] = $eNoteRec;
			$dirInfo = $this->getAbsDirFile($eNoteRec,$previewMode);
			if (is_array($dirInfo))	{
				$notes[] = $dirInfo;
			} else {
				die($dirInfo);
			}

			if ($firstIteration)	{
				$this->setBookConfiguration($this->getBookRecord($eNoteRec['book']));

					// In HTML mode we dont allow the user to specify the location of the preamble so we require it to be present in the folder where the actually used preamble in the file is found:
				if ($mode=='HTML')	{
					$texContent = t3lib_div::getUrl($dirInfo['absFile']);
					$res = $this->setPrePostAmbles($texContent, '','');		// Clear pre/post ambles.
					$field_preamble =dirname($res['oldPreamble']).'/preamble_HTML.tex';
					$field_postamble = dirname($res['oldPostamble']).'/postamble_HTML.tex';
				}
				$firstIteration = FALSE;
			}
		}
		$uniqueIdent = array();
		//$uniqueIdent['title'] = $title;
		$totalRevision = 0;
		foreach($eNoteRecs as $e) {
			$revision = ($previewMode?$e['lastchangedrevision']:$e['lastchangedrevision_live']);
			if($revision > $totalRevision) { $totalRevision = $revision; }
			$uniqueIdent[] = array('uid' => $e['uid'],'lastrevision' => $revision);
		}
		//$uniqueIdent['title'] += ' (Rev. '.$totalRevision.')';
		$uniqueIdent['conf'] = array('preview' => ($previewMode?'true':'false'),'preamble' => $field_preamble,'postamble' => $field_postamble,'boxenv' => $boxEnv);
		$uniqueIdentStr = hash('sha512',serialize($uniqueIdent));
		
		//After this point, additions to $uniqueIdent is NOT taken into account in the unique hash
		$uniqueIdent['title'] = $title;
		$uniqueIdent['revision'] = $totalRevision;
		$source = t3lib_div::getFileAbsFileName($this->dataDir.'temp/'.$uniqueIdentStr);
		if((filemtime($source.'.pdf') || file_exists($source.'.ticket')) && $allowCached) {
			$log = array();
			$log['texFile'] = $source . '.tex';
			$log['cached'] = true;
			return $log;
		} else {
			if (count($notes) && $this->bookdir)	{
				$mergedNoteContent = '';

				// TEMP file:
				$sourceFile = $fileName ? $fileName : $uniqueIdentStr.'.tex';
				$absSourceDir = t3lib_div::getFileAbsFileName($this->dataDir.'temp/');

				// PREAMBLE:
				// $path='/';

				// $preamble = $absSourceDir.'../books/'.$this->bookdir;
				// $count = 0;
				// $field_preamble = str_replace('../', '', $field_preamble);
				// while(!file_exists($preamble . $path . $field_preamble) && $count++ < 5) {
				// 	echo "TESTED: " . $preamble . $path . $field_preamble . "\n";
				// 	$path .= '../';
				// }
				// echo "Found preamble in: " . realpath($preamble . $path . $field_preamble) . chr(10);

				if(!file_exists($absSourceDir.'../books/'.$this->bookdir.'/'.$field_preamble)) {
					$field_preamble = str_replace('../','',$field_preamble);
				 	$field_postamble = str_replace('../','',$field_postamble);
				 }

				$preamble = t3lib_div::getUrl($absSourceDir.'../books/'.$this->bookdir.'/'.$field_preamble);	// TODO: Check if file exists!
				$preamble = $this->includeInputFiles($preamble,dirname($absSourceDir.'../books/'.$this->bookdir.'/'.$field_preamble).'/');
				$preamble = $this->fixPathPrefixes($preamble,'','../books/'.$this->bookdir.'/');

				// Background watermark:
				/*
				$preamble = str_replace('\usepackage{wrapfig}','\usepackage{wrapfig}
				\usepackage[draft]{pdfdraftcopy}
				\draftstring{Licens: Kasper Langt Mellemnavn}
				\draftfontsize{30}', $preamble);
				*/	

				$mergedNoteContent.=chr(10).'% *********** PREAMBLE *************'.chr(10).$preamble;

				// BODY:
				foreach($notes as $eNote)	{
					$texContent = file_get_contents($eNote['absFile']);
					$res = $this->setPrePostAmbles($texContent, '','');
					$texContent = $res['texContent'];

					$texContent = $this->includeInputFiles($texContent,dirname($eNote['absFile']).'/');
									
					// TODO: hyperref skal behandles særskilt:
					$pattern = '/\\\\(ref|eqref|nameref|pageref|label|tref|refA|trefA)([\*\[][^{]*{|{)([^-}]+)}/i';	// Finds all labels/references WITHOUT a prefix
					//$pattern = '/\\\\(ref|eqref|nameref|pageref|label)([\*\[][^{]*{|{)(TN[0-9]+-[^}]+)}/i';	// Finds all labels/reference which HAS a prefix.
					$texContent = preg_replace($pattern, '\\\\$1$2NUID'.$eNote['enoteUid'].'-$3}', $texContent);

					// Processing out special linktags separately for HTML and PDF versions:
					$pattern = '/\\\\(tref|thref|refA|hrefA|trefA|threfA)({([^}]+)})({[^}]+}|)/i';	// Finds all special linktags
					$texContent = preg_replace($pattern, '\\\\href{$1::$3}$4', $texContent);	//... and make them hrefs instead!!

					if ($mode=='HTML')	{
						// For HTML: Fixing pdf/png issues.
						$pattern = '/\\\\(includegraphics)([\*\[][^{]*{|{)([^-}]+)\.pdf}/i';	// Finds all labels/references WITHOUT a prefix
						$texContent = preg_replace_callback(
				    	    $pattern,
					        create_function(
					            // single quotes are essential here,
					            // or alternative escape all $ as \$
					            '$matches',
					            '
									return "\\\\".$matches[1].preg_replace("/trim=[^,]*[,]/","",preg_replace("/,clip/","",$matches[2])).$matches[3].".png}";
								'
					        ),
					        $texContent
					    );
					}

					$texContent = $this->fixPathPrefixes($texContent,'../'.($previewMode?'preview/':'live/').$eNote['relDir'],'../books/'.$this->bookdir.'/');
					$mergedNoteContent.= $this->texContentProcessing($texContent,$mode,$boxEnv);
				}

					// POSTAMBLE
				$postamble = t3lib_div::getUrl($absSourceDir.'../books/'.$this->bookdir.'/'.$field_postamble);	// TODO: Check if file exists!
				$postamble = $this->fixPathPrefixes($postamble,'','../books/'.$this->bookdir.'/');
				$mergedNoteContent.=chr(10).'% *********** POSTAMBLE *************'.chr(10).$postamble;

				if($mode != "HTML") {
				$mergedNoteContent = $this->latexChangeExternalLinksToHref($mergedNoteContent);	
				}		
				$mergedNoteContent = $this->removeNonServerSections($mergedNoteContent);
				// Write generated .tex source file to disk
				//t3lib_div::writeFile($absSourceDir.$sourceFile,$mergedNoteContent);
				file_put_contents($absSourceDir.$sourceFile, $mergedNoteContent);
				// Generate PDF:
				$cmd = $this->execCfg['pdflatex_PRECMD'] ? $this->execCfg['pdflatex_PRECMD'].chr(10) : '';
				$cmd.= 'cd "'.$absSourceDir.'"'.chr(10);
				// TODO: Do check that we are in this folder...?
				$cmd.= $this->execCfg['makeindex']." \"./".preg_replace('/\.tex$/','.idx',$sourceFile).'" 2>&1'.chr(10);
		    	$cmd.= $this->execCfg['pdflatex']." \"./".$sourceFile.'"';
				if($allowCached) {
					shell_exec(t3lib_extMgm::extPath('enoteserver') . "/cli_customGenerate " . substr($sourceFile,0,-4) . " >/dev/null 2>&1 &");
					file_put_contents($source . '.metadata',json_encode($uniqueIdent));
					$log['texFile'] = $absSourceDir.$sourceFile;
					$log['cached'] = true;
					return $log;
				} else {
						# Render twice!! (for TOC etc):
					exec($cmd,$res,$rescode);
					if (!$rescode) {
						exec($cmd,$res);
					}				
					if($rescode > 0) { // Do not remove log if failed... but remove pdf
						exec('rm '. substr($absSourceDir.$sourceFile,0,-3) . '{idx,ilg,ind,out,pdf}');
					} else {
						//Remove temp files
						exec('rm '. substr($absSourceDir.$sourceFile,0,-3) . '{idx,ilg,ind,log,out}');
					}
					$log['lastLog'] = $res;
					$log['returnCode'] = $rescode;
					$log['texFile'] = $absSourceDir.$sourceFile;
					$log['cached'] = false;
					return $log;
				}
			}
		}
	}
	
	/**
	 * Sets new preamble and postamble files in text content.
	 * The preamble and post amble are required to be the first and last lines of the TEX input source which is not a comment line or empty!
	 *
	 * @param string	TEX content
	 * @param string	Preamble filename to set, relative to "../". If empty, it will remove preamble line altogether
	 * @param string	Postamble filename to set, relative to "../". If empty, it will remove postamble line altogether
	 * @return array	Array with information; processed TEX content, error, old pre- and postamble files.
	 */	
	function setPrePostAmbles($texContent, $preamble, $postamble)	{

		$output = array();
			// Split by line:
		$modifiedTexContentLines = t3lib_div::trimExplode(chr(10), $texContent);

			// Preamble, first real line:
		foreach($modifiedTexContentLines as $idx => $line)	{
			if (trim($line) && substr(trim($line),0,1)!="%")	{
				$pattern = '/[[:space:]]*\\\\input{..\/([^}]+)[[:space:]]*/i';
				if (preg_match($pattern, $line, $matches))	{
					$output['oldPreamble'] = $matches[1];
					$modifiedTexContentLines[$idx] = $preamble ? '\input{../'.$preamble.'}' : '';
				} else {
					$output['error'] = 'ERROR: No preamble found!';
				}
				break;
			}
		}

			// Postamble, last real line:
		for($a=count($modifiedTexContentLines);$a>0;$a--)	{
			$idx = $a-1;
			$line = $modifiedTexContentLines[$idx];
			
			if (trim($line) && substr(trim($line),0,1)!="%")	{
				$pattern = '/[[:space:]]*\\\\input{..\/([^}]+)[[:space:]]*/i';
				if (preg_match($pattern, $line, $matches))	{
					$output['oldPostamble'] = $matches[1];
					$modifiedTexContentLines[$idx] = $postamble ? '\input{../'.$postamble.'}' : '';
				} else {
					$output['error'] = 'ERROR: No postamble found!';
				}
				break;
			}
		}
		
			// Set output:
		$output['texContent'] = implode(chr(10),$modifiedTexContentLines);
		return $output;
	}
	
	/**
	 * Prefixes paths in Latex in includegraphics/input
	 *
	 * @param string		TEX content to proces
	 * @param string		Prefix string for resources INSIDE the tex-file folder, (must start with ../)
	 * @param string		Prefix string for resources OUTSIDE the tex-file folder (called common resources), (must start with ../)
	 * @return 	string		Modified TEX content.
	 */	
	function fixPathPrefixes($text,$prefix,$prefixCommon)	{

			// input + includegraphics{../}
			// ORDER IS IMPORTANT: backreferences ../ must be found first, because the 
		$pattern = '/(\\\\(includegraphics|input)[^{]*{)\.\.\/([^}]*)(})/i';
#		preg_match_all($pattern, $text, $matches);
#echo 'common:';
#		print_r($matches);
#print_r($prefixCommon);
		$replacement = '$1'.$prefixCommon.'$3$4';
		$text = preg_replace($pattern, $replacement, $text);

		$pattern = '/(\\\\epsfig{)([^}]*(file|figure)=)([^}]+)(,[^}]*}|})/';
		$replacement = '$1$2' . $prefix . '$4$5';

		$text = preg_replace($pattern, $replacement, $text);

			// input + includegraphics{}
		$pattern = '/(\\\\(includegraphics|input)[^{]*{)([^.][^.][^}]*)(})/i';
#		preg_match_all($pattern, $text, $matches);
#echo 'local:';
#		print_r($matches);
		$replacement = '$1'.$prefix.'$3$4';
		$text = preg_replace($pattern, $replacement, $text);


#		print_r(array($text));			
		return $text;
	}

	function stripKnitr($text) {
	  $matches = preg_split("/(\\\\begin{kframe}|\\\\end{kframe})/ms", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
	  $didMatch = false;
	  foreach($matches as $id => $match) {
	    if($match == "\begin{kframe}" && $matches[$id + 2] == "\end{kframe}") {
	      unset($matches[$id]);
	      unset($matches[$id + 2]);

	      $matches2 = preg_split("/(\\\\begin{alltt}|\\\\end{alltt})/ms", $matches[$id + 1], -1, PREG_SPLIT_DELIM_CAPTURE);
	      
	      foreach($matches2 as $id2 => $match2) {
	      	if($matches2[$id2] == "\begin{alltt}" && $matches2[$id2 + 2] == "\end{alltt}") {

	      		$matches2[$id2] = "\begin{verbatim}";
	      		$matches2[$id2 + 2] = "\end{verbatim}";

	      		$matches2[$id2 + 1] = preg_replace("/\\\\[a-zA-Z]+{([^}]+)}/", "$1", $matches2[$id2 + 1]);
	      	}
	      }
	      $matches[$id + 1] = implode("", $matches2);

	      $didMatch = true;
	    }
	  }
	  $newText = implode("", $matches);

	  if($didMatch) {
	    $newText = $this->stripKnitr($newText);
	  }

	  return $newText;
	}

	/**
	 * 
	 *
	 * @param 
	 * @return
	 */	
	function texContentProcessing($modifiedTexContent,$mode,$boxEnv=array())	{
		if (!$this->bookdir)	{
			die( "No common dir set".chr(10));
		}

		// Insert subsections before all box-environments and bodytext sections:
		$pattern = '/([\r\n][ \t]*\\\\begin{('.implode('|',array_keys($this->LaTeX_boxEnvironments)).')})(.*?)(\\\\end{('.implode('|',array_keys($this->LaTeX_boxEnvironments)).')})/ms';
		$documentSplit = preg_split($pattern,$modifiedTexContent,-1,PREG_SPLIT_DELIM_CAPTURE);

		$modifiedTexContent = '';

		for ($i=0; $i < count($documentSplit); $i=$i+6)	{
			$eqCount = 0;

			$body = $this->removeNoticeEnv($documentSplit[$i],$mode);
			$bEnv = $this->removeNoticeEnv($documentSplit[$i+1].$documentSplit[$i+3].$documentSplit[$i+4],$mode);

			switch($mode)	{
				case 'HTML':
						// Insert subsections before chapter, section and subsection headlines (subsubsection is reserved!!!)
					$pattern = '/([%]?)\s*\\\\(chapter|section|subsection'.(count($this->LaTeX_divCmdEnvironments)?'|'.implode('|',array_keys($this->LaTeX_divCmdEnvironments)):'').')[{\[]/i';
					$replacement = '${1}'.chr(10).'\\subsubsection{====MARKER====}'.chr(10).'${0}';
					$body = preg_replace($pattern, $replacement, $body);

						// Put together body and bEnv again:
					$modifiedTexContent.= 
									(trim($body) ? chr(10).'\\subsubsection{====MARKER====}'.chr(10).$body : '').
									(trim($bEnv) ? chr(10).'\\subsubsection{====MARKER====}'.chr(10).$bEnv : '');
				break;
				case 'composite':
					$modifiedTexContent.= chr(10).'% ************************** BODY ***************************'.chr(10);
					if (in_array('_body',$boxEnv))	{
						$modifiedTexContent.=$body;
					} else {
						$pattern = '/\\\\(setcounter|chapter|section|subsection){[^}]*}({[^}]*}|)[^\n]*/i';
						preg_match_all($pattern, $body, $matches);
						foreach($matches[0] as $id => $header) {
							$currentLevel = $this->headerLevels[$matches[1][$id]];
							$emptySection = false;
							for($j = 6; $j + $i < count($documentSplit) ; $j = $j+6) {
								if(in_array($documentSplit[$i+$j-1], $boxEnv)) {
									break;
								}

								$pattern = '/\\\\(chapter|section|subsection){[^}]*}({[^}]*}|)[^\n]*/i';
								$match = array();
								preg_match($pattern, trim($documentSplit[$i+$j]), $match);
								if($match && strpos(trim($documentSplit[$i+$j]), $match[0]) == 0) {
									if($this->headerLevels[$match[1]] <= $currentLevel) {
										$emptySection = true;
										break;
									} else {
										break;
									}
								} else {
									if($i + $j + 6 > count($documentSplit)) {
										$emptySection = true;
										break;
									}
									continue;
								}

							}
							if(!$emptySection || $matches[1][$id] == 'setcounter') {
								$modifiedTexContent .= $header . chr(10);
							} else {
								$modifiedTexContent .= '\refstepcounter{'.$matches[1][$id].'}';
							}

						}
						//$modifiedTexContent.=implode(chr(10), $matches[0]);
						$eqCount = substr_count($body,'\begin{equation}')-substr_count($body,'\nonumber');
						$modifiedTexContent.= str_repeat('\refstepcounter{equation}'.chr(10), $eqCount);
					}

					$boxEnvHeader = chr(10).'% ************************** BoxEnvironment: '.$documentSplit[$i+2].' ***************************'.chr(10);
					if (in_array($documentSplit[$i+2],$boxEnv))	{
						$modifiedTexContent .= $boxEnvHeader;
						$modifiedTexContent.= $bEnv;
					} else {
						$modifiedTexContent .= $boxEnvHeader;
						$modifiedTexContent.= $this->LaTeX_boxEnvironments[$documentSplit[$i+2]]['PDFExclAlt'].chr(10);
						$eqCount = substr_count($bEnv,'\begin{equation}')-substr_count($bEnv,'\nonumber');
						$modifiedTexContent.= str_repeat('\refstepcounter{equation}'.chr(10), $eqCount);

#						$pattern = '/(\\\\label[^{]*{)([^}]*)(})/i';
#						preg_match_all($pattern, $modifiedTexContent, $matches);
#						debug($matches);

#						$replacement = '$1'.$prefix.'$2$3';
#						$text = preg_replace($pattern, $replacement, $text);
						#debug(array($text));			
#						return $text;

					}
				break;
			}
		}

		$modifiedTexContent = $this->stripKnitr($modifiedTexContent);
		
		return $modifiedTexContent;
	}

	function removeNoticeEnv($modifiedTexContent,$mode)	{
		#return $modifiedTexContent;
		
		if ($mode!='HTML')	{
			$noticeEnvs = array('vink','facit');
		
			$pattern = '/([\r\n][ \t]*\\\\begin{('.implode('|',$noticeEnvs).')})(.*?)(\\\\end{('.implode('|',$noticeEnvs).')})/ms';
			$documentSplit = preg_split($pattern,$modifiedTexContent,-1,PREG_SPLIT_DELIM_CAPTURE);
			$modifiedTexContent = '';
			for ($i=0; $i < count($documentSplit); $i=$i+6)	{
				$body = $documentSplit[$i];
	//			$bEnv = $documentSplit[$i+1].$documentSplit[$i+3].$documentSplit[$i+4];

				$modifiedTexContent.=$body;
			}
		}
		return $modifiedTexContent;
	}
	

	function includeInputFiles($texContent,$baseDir)	{		// TODO: Should detech if 
		$pattern = '/('.chr(10).'[ ]*\\\\(input)[^{]*{)([^}]*)(})/i';		// VERY Unstable. It eats a character before which hopefully is just a whitespace. Otherwise we have trouble.
																		
#		preg_match_all($pattern, $texContent, $matches);
#debug($matches);		

		$parts = preg_split($pattern, chr(10).chr(10).$texContent, 10000, PREG_SPLIT_DELIM_CAPTURE);
		$texContent = '';
		for ($i=0; $i < count($parts); $i=$i+5)	{
			$texContent.= $parts[$i];
			if ($parts[$i+3])	{
				$includeFile = t3lib_div::resolveBackPath($baseDir.$parts[$i+3]);	// TODO: Test the file exists and TEST that we may include it!!!
				if (!is_file($includeFile)) {
					if(is_file($includeFile . ".tex")) {
						$includeFile = $includeFile . ".tex";
						echo "Debug: Added .tex to input path\n";
					}
				}
					// TODO: Make it sensitive, so include files can have no tex extension...
				$texContent.= chr(10).t3lib_div::getUrl($includeFile).chr(10);
			}
		}

		return $texContent;
	}
	
	function LateXCmdUsageStat($texContent)	{
		$cmdArray=array('cmd'=>array(),'env'=>array());

		preg_match_all('/\\\\[[:alnum:]_]+/i',$texContent,$matches);
		foreach($matches[0] as $cmd)	{
			$cmdArray['cmd'][$cmd]++;
		}
		arsort($cmdArray['cmd']);			// Sort by number of instances
		// ksort($cmdArray['cmd']);		// Sort by command
		
		preg_match_all('/\\\\begin{([^}]+)}/i',$texContent,$matches);
		foreach($matches[1] as $envName)	{
			$cmdArray['env'][$envName]++;
		}
		ksort($cmdArray['env']);
		
		return $cmdArray;
	}

	function latexChangeExternalLinksToHref($texContent)	{
		global $_labelIndex;

		// First, find all labels in document (there should not be more than one of each!!)
		preg_match_all('/\\\\(label)([\*\[][^{]*{|{)([^}]+)}/i',$texContent,$matches);
		$_labelIndex=array();
		foreach($matches[3] as $labelName)	{
			$_labelIndex[$labelName]++;
		}

		// href processing:
		$pattern = '/\\\\(href)([\*\[][^{]*{|{)(\w+)::([^}]+)}({([^}]+)})?/i';
		$texContent = preg_replace_callback(
    	    $pattern,
	        create_function(
	            // single quotes are essential here,
	            // or alternative escape all $ as \$
	            '$matches',
	            '
	            	if(isset($GLOBALS["_labelIndex"][$matches[4]]) && $matches[3] == "tref") {
	            		return $matches[6] . " \\\\ref{" . $matches[4] . "}";
	            	} elseif (substr($matches[4],0,4)=="NUID")	{
						// Falling through to \ref treatment below
						return $matches[6] . " \\\\ref{".$matches[4]."}";
					}
					return "\\\\".$matches[1].$matches[2].$matches[3]."::".$matches[4]."}".$matches[5];
				'
	        ),
	        $texContent
	    );

		// TODO: |hyperref skal håndteres særskilt
		// nameref understøttes pt ikke
		// pageref giver ikke mening med URL link... (understøttes ikke)
		// TODO: eqref understøttes og burde kapsles ind i ()
		$pattern = '/\\\\(ref|eqref)([\*\[][^{]*{|{)([^}]+)}/i';

		// Replace all ref/eqrefs with hrefs in case theyre not present in the composite eNote
		$texContent = preg_replace_callback(
		        $pattern,
		        create_function(
		            // single quotes are essential here,
		            // or alternative escape all $ as \$
		            '$matches',
		            '
						if (isset($GLOBALS["_labelIndex"][$matches[3]]))	{
							return "\\\\".$matches[1].$matches[2].$matches[3]."}";
						} else {
							//return "\\\\href{'.$this->showUrl.'".$matches[3]."}{(TODO:".str_replace("_","\\_",$matches[3]).")}";
							return "\\\\href{'.$this->showUrl.'".$matches[3]."}{(online)}";
						}
					'
		        ),
		        $texContent
		    );
		
		return $texContent;
	}

	function removeNonServerSections($mergedNoteContent)	{

			// Matching "exclude code":
		$preg = '/(% ###SERVER_EXCLUDE_BEGIN###)(.*?)(% ###SERVER_EXCLUDE_END###)/ms';
		if (preg_match_all($preg,$mergedNoteContent,$matches))	{
		#	print_r($matches);
			$mergedNoteContent = preg_replace($preg,'',$mergedNoteContent); 
		}
		
		return $mergedNoteContent;
	}


	/****************************************
	 ***
	 *** HTML + ePUB
	 ***
	 ***************************************/

	/**
	 * Assuming that lateXML has been processing the tex file in some way, the task of this function is to convert that output to a PHP array with meta information as well as HTML, ready for recompilation in page display.
	 * This particular function is compatible with the cowboy-method of conversion which means; LateXML processes a modified Tex-file (with \subsubsection markers inserted between environments to divide the document and attach labels) and converts XML to HTML with latexpost. Both files (XML/HTML + AUX) are read to generate this array.
	 * In principle this function should be substituted at a later time with an more solid function as soon as a more robust workflow around LateXML is found. But currently we don't have time to do it properly with LateXML and the time investment in making it right seems large and unknown.
	 * 
	 * Works only on Preview files!
	 */
	function latexmlOutput2HTMLStruct_eNote($dirInfo,$enoteUid)	{
		if (!is_array($dirInfo))	return "ERROR: dirInfo input variable was not an array!";
		
		$loadBookCfg = $this->loadBookConfiguration($enoteUid);
		if ($loadBookCfg) die ("ERROR: ".$loadBookCfg);
		
		/* Output array:

		documentParts contains keys:
			HTML:id + XML:id = (INTERNAL USE)
			labelsInside = array of key=>values which are LaTeX labels => their output string(s) as found inside the section (output strings found via from AUX-file).
			idsInside = num array of HTML id values in section. Used for correcting links (<a> tags) during output: If an ID is linked to and the ID is within the sections shown, then the link just jumps to another position on page, otherwise it will open in a new window. So idsInside is depending on the particular way LaTeX and the links inside is converted to HTML.
			toplabel = Label in the top of the section if any. Used to create $idMap
			HTML = HTML content. This is cleaned up in various ways, modified depending on section type.
			type = Section type; bevis, saet, etc... This is detected based on analysis of the HTML!!!
			HeaderText = If the section has a headline (\section, \subsection etc), the text is this. Used to generate a table of contents. This is detected based on analysis of the HTML!!!
			HeaderLevel = integer. Indent level of the HeaderText, if any

		idIndex = key=>values which are HTML-id (from idsInside) as keys pointed to the array index number of the corresponding section in $documentParts. Used with idsInside for link-correction (to identify in which section a given ID is pointing to)
		idMap = key=>values which are HTML-ids matching "toplabel" as keys and the label output string as value. Used in link generation to make a meaningful name to links to sections it seems. 

		*/

			// First, get the file pointet to. Assumptions are that the base is pointing to the XML file, from here the HTML version is inside HTMLOUTPUT/:
		$contentXML = t3lib_div::getUrl(t3lib_div::getFileAbsFileName($this->dataDir.'temp/note_'.$enoteUid.'_HTML.tex.xml'));
		$contentHTML = t3lib_div::getUrl(t3lib_div::getFileAbsFileName($this->enoteHTMLpath.$enoteUid).'/index.html');
		$contentAUX = t3lib_div::getUrl(substr(t3lib_div::getFileAbsFileName($this->dataDir.'temp/note_'.$enoteUid.'_HTML.tex'),0,-4).'.aux');
		echo substr(t3lib_div::getFileAbsFileName($this->dataDir.'temp/note_'.$enoteUid.'_HTML.tex'),0,-4).'.aux';
#debug(array($contentXML,$contentHTML,$contentAUX));
		// Cleaning up the HTML generally for irrelevant classes, tokens we don't want etc.
		$contentHTML = str_replace('§','',$contentHTML);
			// Remove irrelevant attribute: <div ... class="para" ... > => <div ...>
		$contentHTML = preg_replace("/(<div[^>]*)class=\"para\"([^>]*>)/ms","$1$2",$contentHTML); 
			// Remove irrelevant attribute: <p ... class="p" ... > => <p ...>
		$contentHTML = preg_replace("/(<p[^>]*)class=\"p\"([^>]*>)/ms","$1$2",$contentHTML); 
			// Remove irrelevant attribute: <span ... style="" ... > => <span ...>
		$contentHTML = preg_replace("/(<span[^>]*)style=\"\"([^>]*>)/ms","$1$2",$contentHTML); 
			// Remove irrelevant attribute: <img ... alt="..." ... > => <img ...>	NOTICE: This is politically incorrect since this attribute should be available for screen readers. If you need that just remove the line. It is only trying to save some bandwidth!
		$contentHTML = preg_replace("/(<img[^>]*)alt=\"[^\"]*\"([^>]*>)/ms","$1$2",$contentHTML); 
		
			// Setup: Fix nesting issues of <div> tags (because chapters encapsulate sections encapsulate subsections etc. we have to remove false end-tags as a minimum.):
		$htmlParser = t3lib_div::makeInstance('t3lib_parsehtml');
		$tags = array();
		$tags['div']['nesting']=1;

#debug(array($contentXML));
		// SPLITTING: The XML and HTML documents at split "in unison" by the ====MARKER==== string. We need them to match up
		// From the HTML we obviously need the HTML, from the XML we like to extract stuff like labels attributes, refnum and xml-ids.

		// Splitting XML on:
		//		<subsubsection refnum="9.1.0.4" xml:id="Ch9.S1.SS1.SSS4" labels="LABEL:saet.hovedstruktur1">
	    //		<title>====MARKER====</title>
		$partsXML = preg_split("/(<subsubsection[^>]*>[^<]*)(<title[^>]*>====MARKER====<\/title>)/", ' '.$contentXML.' ',10000, PREG_SPLIT_DELIM_CAPTURE);
		unset($partsXML[0]);
#	debug($partsXML);		

#debug(array($contentHTML));
		// Splitting HTML on:		
		//		<div class="subsubsection" id="Ch9.S0.SS0.SSS1">
		//		<h5 class="title subsubsection-title">Â§ 9.0.0.1. ====MARKER====</h5>
			// NOTICE: In e-math project the tag was <h5> used for subsection, now it is <h4>. This must depend on the preamble!
		$parts = preg_split("/(<div class=\"subsubsection[^\"]*\"[^>]*>)([^>]*>[^=]*====MARKER====<\/h[2|3|4|5]>)/", ' '.$contentHTML.' ',10000, PREG_SPLIT_DELIM_CAPTURE);

#		unset($parts[0]);	// Remove header, we don't need that.
#	debug($parts);		

			// Parsing HTML and XML in parallel and builds an array of the individual sections that our markers indicate
		$idIndex = array();
		$idMap = array();
		$documentParts = array();
		$counter = 0;
		foreach($parts as $key=>$value)	{
			if ($key%3==1)	{
				$data = array();

					// HTML id:
				$matches = array();
				preg_match('/id="([^"]*)"/' ,$parts[$key] , $matches);
				$data['HTML:id'] = $matches[1];

					// XML id:
				$matches = array();
				preg_match('/xml:id="([^"]*)"/' ,$partsXML[$key] , $matches);
				$data['xml:id'] = $matches[1];

				if ($data['HTML:id']!==$data['xml:id'])	{
					debug(array($data['HTML:id'],$data['xml:id']));
					return "TEKNISK FEJL: Kunne ikke vise indholdet fordi XML og HTML filen ikke stemte overens.";
				}

					// Find all LABELS attributes belonging to this section in XML. Any reference to one of these labels should link us to this document:
					// After that, uses the AUX file to match the labels to reference numbers of sections, equations, boxes etc.
				$matches = array();
				preg_match_all('/labels="([^"]*)"/' ,$partsXML[$key].$partsXML[$key+2] , $matches);
				$temp_labels = t3lib_div::trimExplode(' ',implode(' ',$matches[1]));

					// looking up index numbers for labels from AUX file:
					//				\newlabel{hvad.diff21}{{9.A}
				$data['labelsInside'] = array();
				foreach($temp_labels as $labelvalue)	{
					$matches = array();
					preg_match('/newlabel\{'.substr($labelvalue,6).'\}\{\{([^\}]+)\}/' ,$contentAUX , $matches);
					if(substr($labelvalue,6))	{$data['labelsInside'][substr($labelvalue,6)] = $matches[1];}
				}

					// Find all IDS belonging to this section and assign the index from documentParts in an index:
				$matches = array();
				preg_match_all('/id="([^"]*)"/' ,$parts[$key].$parts[$key+2] , $matches);
				$data['idsInside'] = t3lib_div::trimExplode(' ',implode(' ',$matches[1]));
				foreach($data['idsInside'] as $idvalue)	{
					$idIndex[$idvalue] = $counter;		// A global index
				}

					// Extracts if there is a label attached to the section top:
				$matches = array();
				preg_match('/labels="([^" ]*)"/' ,$partsXML[$key] , $matches);
				$data['toplabel'] = str_replace('LABEL:','',$matches[1]);
					// Map an id to a label output string:
				if ($data['labelsInside'][$data['toplabel']])	{
					$idMap[$data['HTML:id']] = $data['labelsInside'][$data['toplabel']];
				}
				
					// The output HTML is cleaned up:
				$data['HTML'] = $htmlParser->HTMLcleaner($parts[$key].$parts[$key+2], $tags,TRUE);	// Skipping the ====MARKER==== code, but keeping the section div (because sometimes that will encapsulate something, othertimes not, so we leave it.

					// Header:
				$matches = array();
				if (preg_match('/\<h([234])[^>]*\>(.*?)<\/h[234]>/msi' ,substr($data['HTML'],0,400) , $matches))	{
					$data['HeaderLevel'] = $matches[1]-2;
					$data['HeaderText'] = $matches[2];
				}
				
					// Matching notice environments:
				$preg = '/<p[[:space:]]*>(====('.strtoupper(implode('|',array_keys($this->LaTeX_noticeEnrironments))).')-BEGIN====)<\/p[[:space:]]*>[[:space:]]*<\/div[^>]*>(.*?)(====('.strtoupper(implode('|',array_keys($this->LaTeX_noticeEnrironments))).')-END====)<\/p[[:space:]]*>/ms';
				if (preg_match_all($preg,$data['HTML'],$matches))	{
					$data['HTML'] = preg_replace($preg,'<!--###NOTICEENV-BEGIN:$2###--><table border="0" cellpadding="2" cellspacing="0" class="noticeenv noticeenv-$2" style=""><tr><td class="iconcell" valign="top"<div class="iconcell"><img src="###NOTICE_ENV_ICON_PATH###$2.png" width="50"></div></td><td class="contentcell" valign="top"><p>$3</p></td></tr></table><!--###NOTICEENV-END:$2###-->',$data['HTML']); 
				}
					// Matching "qrcode" environment:
				$preg = '/(====QRCODE-BEGIN====)([[:alnum:]]+)(.*?)(====QRCODE-END====)/ms';
				if (preg_match_all($preg,$data['HTML'],$matches))	{
					$data['HTML'] = preg_replace($preg,'',$data['HTML']); 
					foreach($matches[0] as $kk => $vv)	{
						$data['HTML'].= '<div class="qrcode">MULTIMEDIALINK HERE: http://qr.dtu.dk/'.$matches[2][$kk].', title="'.$matches[3][$kk].'"</div>';
					}
				}


					// Matchings box environments:
					/*		An example:
										 <div id="Ch999.S1.SS0.SSS1.p1">
										        <p><span class="text HASH(0xb74d34) bold">Eksempel 999.1:
										        Hello World!</span></p>
										      </div>
					*/
				$tempEnvironments = $this->LaTeX_boxEnvironments+$this->LaTeX_divCmdEnvironments;

				$preg = '/<p[[:space:]]*><span[[:space:]]+class="text HASH[^"]+">('.strtoupper(implode('|',array_keys($tempEnvironments))).')(|[^[:alnum:]][[:space:]]*([0-9]*\.?[0-9]*):?(.*?))\<\/span\>\<\/p\>/';
				if (preg_match($preg,substr($data['HTML'],0,1000),$matches))	{
					$titleString = $tempEnvironments[strtolower($matches[1])]['title'].
									(trim($matches[3]) ? ' '.$matches[3] : '').
									(trim($matches[4]) ? ': '.$matches[4] : '');
					$data['HTML'] = preg_replace($preg,'<h3>'.$titleString.'</h3>',$data['HTML']); 
					$data['HTML'] = '<div class="boxdivenv boxdivenv-'.strtolower($matches[1]).'">'.$data['HTML'].'</div>';
					$data['type'] = strtolower($matches[1]);
				}
					// Clean up to XHTML with tidy:
#					debug($this->bookEncoding);
				$data['HTML'] = $this->tidyHTML($data['HTML'],'utf8');
#				$data['HTML'] = str_replace('&euro;&permil;','',$data['HTML']);
				
					// Set document data:
				$documentParts[] = $data;
				$counter++;
			}
		}
		foreach($documentParts as $idx => $part)	{
				// Processing A-tag:
			$blocks = $htmlParser->splitIntoBlock('a',$part['HTML']);
				// For each A-tag, find out if the link is on THIS page or on another one, if so, link to that page... (opening in new window)
			foreach($blocks as $k => $value){
				if (intval($k)%2)	{
					$matches = array();
					
					if (preg_match('/href[[:space:]]*=[[:space:]]*"[^\#]*\#([^"]+)"/' ,$value , $matches))	{
						$linkString = $idMap[$matches[1]] ? $idMap[$matches[1]] : strip_tags($value);
						$blocks[$k] = '<a href="#'.htmlspecialchars($matches[1]).'">'.$linkString.'</a>';
#						debug(array($value,$blocks[$k],$matches),'BEFORE-AFTER');
					} elseif(preg_match('/href[[:space:]]*=[[:space:]]*"([^"]+)"/' ,$value , $matches))	{
#						if (substr($matches[1],0,4)=="NUID")	{
#							$blocks[$k] = '<a href="'.htmlspecialchars($this->showUrl.$matches[1]).'">'.strip_tags($value).'</a>';
#						}
							# External URLs are ok...
#							debug(array($value,$blocks[$k],$matches),'BEFORE-AFTER');
					}
				}
			}					

			$documentParts[$idx]['HTML'] = implode('',$blocks);	
		}
		//print_r($documentParts);
		return array(
			'idIndex' => $idIndex,
			'documentParts' => $documentParts,
			'idMap' => $idMap
		);
	}
	
	/**
	 * 
	 *
	 * @param 
	 * @return
	 */	
	function createCompositeEPub($eNotes,$stylesheet,$boxEnv,$previewMode)	{
		
		$notes =array();
		foreach($eNotes as $uid)	{
			$dirInfo = $this->getAbsDirFile($this->getEnoteRecord($uid),$previewMode);
			if (is_array($dirInfo))	{
				$notes[] = $dirInfo;
			} else {
				die($dirInfo);
			}
		}
#debug($notes);		
		if (count($notes))	{


			$sourceDir = 'TEMP_ePub_'.time();
			$absSourceDir = t3lib_div::getFileAbsFileName($this->dataDir.'temp/'.$sourceDir.'/');
			t3lib_div::mkdir($absSourceDir);
			t3lib_div::writeFile($absSourceDir.'mimetype','application/epub+zip');
			t3lib_div::mkdir_deep($absSourceDir,'META-INF/');
			t3lib_div::writeFile($absSourceDir.'META-INF/container.xml',
			trim('
<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
	<rootfiles>
		<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
	</rootfiles>
</container>
'));			

			t3lib_div::mkdir_deep($absSourceDir,'OEBPS/images/');
			t3lib_div::writeFile($absSourceDir.'OEBPS/stylesheet.css',t3lib_div::getUrl($absSourceDir.'../../books/'.$this->bookdir.'/'.$stylesheet));
			copy(t3lib_extMgm::extPath('enoteserver').'sample_epub/OEBPS/page-template.xpgt',$absSourceDir.'OEBPS/page-template.xpgt');
			t3lib_div::writeFile($absSourceDir.'OEBPS/title_page.xhtml',trim('
			<?xml version="1.0" encoding="iso-8859-1"?>
			<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
			<html xmlns="http://www.w3.org/1999/xhtml">
			<head>
				<title>Title Page</title>
			<link href="stylesheet.css" type="text/css" rel="stylesheet" />
			<link rel="stylesheet" type="application/vnd.adobe-page-template+xml" href="page-template.xpgt"/>
			</head>
			<body>
			<div>
			  <p>&nbsp;</p>

			  <h2>Sample e-math Book</h2>

			  <h2>A Sample .epub Book</h2>

			  <p>&nbsp;</p>

			  <h3>By Kasper</h3>
			</div>
			</body>
			</html>'));
			
			$toc = array();
			foreach($notes as $id => $eNote)	{
				$chapterContent = '';
				
				$structure = $this->latexmlOutput2HTMLStruct_eNote($eNote,$eNote['enoteUid']);

				if (is_array($structure))	{
					foreach($structure['documentParts'] as $part)	{
							// Box environments:
						if ($this->LaTeX_boxEnvironments[$part['type']] && in_array($part['type'],$boxEnv))		{
							$chapterContent.=$part['HTML'];
#							debug($part);
						}
							// Bodytext:
						if (!trim($part['type']) && in_array('_body',$boxEnv))		{
							$chapterContent.=$part['HTML'];
							#							debug($part);
						}
						
						
						
#						$HTML = $part['HTML'];
							// Prefixing relative paths:
					#	$HTML = $htmlParser->prefixResourcePath($this->util->enoteHTMLpath.$this->internal['currentRow']['uid'].'/',$HTML);

					}
					t3lib_div::mkdir_deep($absSourceDir,'OEBPS/images/'.$eNote['enoteUid'].'/');
					list($chapterContent,$imageList) = $this->fixIMGPathPrefixes($chapterContent,'images/'.$eNote['enoteUid'].'/');
					foreach($imageList as $img)	{
						
						debug(copy(t3lib_div::getFileAbsFileName(t3lib_div::resolveBackPath(($previewMode?$this->dataDir.'preview/_HTML/':'live/_HTML/').$eNote['enoteUid'].'/'.$img)), $absSourceDir.'OEBPS/images/'.$eNote['enoteUid'].'/'.basename($img)));
					}
					
					t3lib_div::writeFile($absSourceDir.'OEBPS/chap'.$id.'.xhtml',trim('<?xml version="1.0" encoding="utf-8"?>
					<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
					<html xmlns="http://www.w3.org/1999/xhtml">
					<head>
					<title>Chapter 1</title>
					<link href="stylesheet.css" type="text/css" rel="stylesheet" />
					<link rel="stylesheet" type="application/vnd.adobe-page-template+xml" href="page-template.xpgt"/>
					</head>
					<body>
					<div class="enoteHTML">'.$this->cleanEncoding($chapterContent).'</div>
					</body>
					</html>'));
					$toc[] = array('title' => 'Chapter '.$id, 'file' => 'chap'.$id.'.xhtml');
				}
			}

			$bookTitle = 'Kaspers test '.time();
			$author = 'Kasper Skaarhoej';
			$tocOutput = '<?xml version="1.0" encoding="UTF-8"?>
			<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
			  <head>
			    <meta name="dtb:uid" content="enoteserver_'.time().'"/>
			    <meta name="dtb:depth" content="1"/>
			    <meta name="dtb:totalPageCount" content="0"/>
			    <meta name="dtb:maxPageNumber" content="0"/>
			  </head>
			  <docTitle>
			    <text>'.$bookTitle.'</text>
			  </docTitle>
			  <navMap>
			    <navPoint id="title_page" playOrder="1">
			      <navLabel>
			        <text>Title Page</text>
			      </navLabel>
			      <content src="title_page.xhtml"/>
			    </navPoint>';
			foreach($toc as $id => $chapter)	{
				$tocOutput.='
				    <navPoint id="chapter'.$id.'" playOrder="'.($id+2).'">
				      <navLabel>
				        <text>'.htmlspecialchars($chapter['title']).'</text>
				      </navLabel>
				      <content src="'.htmlspecialchars($chapter['file']).'"/>
				    </navPoint>';
			}
			$tocOutput.= '  </navMap>
			</ncx>';
			t3lib_div::writeFile($absSourceDir.'OEBPS/toc.ncx',$tocOutput);
			
			$contentOPF = '<?xml version="1.0"?>
			<package version="2.0" xmlns="http://www.idpf.org/2007/opf"
			         unique-identifier="BookId">
			 <metadata xmlns:dc="http://purl.org/dc/elements/1.1/"
			           xmlns:opf="http://www.idpf.org/2007/opf">
			   <dc:title>'.$bookTitle.'</dc:title> 
			   <dc:creator opf:role="aut">'.$author.'</dc:creator>
			   <dc:language>en-US</dc:language> 
			   <dc:rights>Public Domain</dc:rights> 
			   <dc:publisher>XXXXXXXXXXX</dc:publisher> 
			   <dc:identifier id="BookId">urn:uuid:XXXXXXXXX.com'.time().'</dc:identifier>
			 </metadata>
			 <manifest>
			  <item id="ncx" href="toc.ncx" media-type="text/xml" />
			  <item id="style" href="stylesheet.css" media-type="text/css" />
			  <item id="pagetemplate" href="page-template.xpgt" media-type="application/vnd.adobe-page-template+xml" />
			  <item id="titlepage" href="title_page.xhtml" media-type="application/xhtml+xml" />';
			foreach($toc as $id => $chapter)	{
				$contentOPF.= '<item id="chapter'.$id.'" href="'.htmlspecialchars($chapter['file']).'" media-type="application/xhtml+xml" />';
			}
			 $contentOPF.= '</manifest>
			 <spine toc="ncx">
			  <itemref idref="titlepage" />';
			foreach($toc as $id => $chapter)	{
			  $contentOPF.= '<itemref idref="chapter'.$id.'" />';
		}
			$contentOPF.= '
			 </spine>
			</package>';
			t3lib_div::writeFile($absSourceDir.'OEBPS/content.opf',$contentOPF);
			
						# Generate PDF:
			$cmd.= 'cd "'.$absSourceDir.'"'.chr(10);
			$cmd.= $this->execCfg['zip']." -0 ../".$sourceDir.".epub ./mimetype".chr(10);
			$cmd.= $this->execCfg['zip']." -r ../".$sourceDir.".epub ./META-INF".chr(10);
			$cmd.= $this->execCfg['zip']." -r ../".$sourceDir.".epub ./OEBPS".chr(10);

			exec($cmd,$res);
			return array($this->dataDir.'temp/'.$sourceDir.'.epub',$res);
		}		
	}
	
	function fixIMGPathPrefixes($text,$prefix)	{
		$pattern = '/(<img[^>]+src[[:space:]]*=[[:space:]]*")([^"]+\/([^\/"]+))("[^>]*>)/s';
		preg_match_all($pattern, $text, $matches);
#		debug($matches);
#exit;
		$replacement = '$1'.$prefix.'$3$4';
		$text = preg_replace($pattern, $replacement, $text);

#		debug(array($text));			
#		return $text;

#debug($images);
		return array($text, $matches[2]);
	}
	
	function cleanEncoding($text)	{	// LORTE work-around fordi HTML koden åbenbart indeholde urigtig UTF-8....
		$cs = t3lib_div::makeInstance('t3lib_cs');
		return $cs->utf8_encode($cs->utf8_decode($text,'iso-8859-1'),'iso-8859-1');
	}





	
	var $repoDirectories = array("svn"=>array(), "git"=>array());
	function getAllRepos($startDir){
		if(substr($startDir,-1) != "/") {
			$startDir .= "/";
		}
		$list = scandir($startDir);
		foreach($list as $el) {
			if (is_dir($startDir . $el) && $el !== ".." && $el !== "." && !is_link($startDir . $el)) {
				if ($el == ".svn") {
					$this->repoDirectories['svn'][] = $startDir;
					break;
				} elseif ($el == ".git") {
					$this->repoDirectories['git'][] = $startDir;
					break;
				} else {
					$this->getAllRepos($startDir . $el);
				}
			} 
		}
		return $this->repoDirectories;
	}


	function updateAllRepos() {
		$enoteDir = t3lib_div::getFileAbsFileName($this->dataDir . "preview/");
		$repoDirectories = $this->getAllRepos($enoteDir);
		
		foreach($repoDirectories as $type => $list) {
			switch($type) {
				case "svn":
					foreach($list as $dir) {
						# SVN update:
						echo "Updating SVN in " . $dir . chr(10);
						exec("svn cleanup " . $dir);
						$cmd = $this->execCfg['svn'].' update '.$this->execCfg['svnUSERPASSoptions'].' --accept theirs-full "'.$dir.'"';
						$res = array();
						exec($cmd,$res);
					}
				break;
				case "git":
					foreach ($list as $dir) {
						$dir = substr($dir,0, -1);
						$dir_work = substr($dir, 0, -6);
						$dir = $dir . "/";
						$dir_work = $dir_work . "/";

						/*if (!is_dir($dir)) {
							echo "Creating dir " . $dir . chr(10);
							mkdir($dir);
						}*/
						if(substr($dir, -7) !== "-clean/") {
							echo "Dir " . $dir . " not named -clean. skipping.\n";
							continue;
						}

						echo "Updating GIT in " . $dir . chr(10);
						$cmd = "cd " . $dir . chr(10);
						//$cmd .= "git stash".chr(10). "git pull -Xtheirs" . chr(10). "git merge -Xours stash@{0}";
						$cmd .= "git reset --hard" . chr(10) . "git clean -f" . chr(10) . "git pull" . chr(10);
						$cmd .= "rsync -auv " . $dir . " " . $dir_work . chr(10);
						$res = array();
						system($cmd);
					}
				break;
				default:
					echo "Not defined repo type" . chr(10);
			}
		}
	}

	// If an eNote contains references to external files via \input{} statements,
	// a simple status from its own directory will not reveal the updates.
	function noteHasChanged($rec, $absFile, $type) {
		$changed = false;
		$checked = array();
		$match = preg_match_all("/\\\\input{([^}]+)}/", file_get_contents($absFile), $matches);
		$inputFiles = $matches[1];
		foreach ($inputFiles as $file) {
			$path = t3lib_div::resolveBackPath(dirname($absFile) . "/" . $file);
			if(substr_compare($path, ".tex", -3) !== 0) {
				$path .= ".tex";
			}
			if(is_file($path) && !in_array(dirname($path), $checked)) {
				$checked[] = dirname($path);
				$rev = $this->repoStatus(dirname($path), $type);
				if ($rev['time'] > $rec['lastgeneratedflag']) {
					echo "Included file(s) from " . dirname($path) . " changed " .  ($rev["time"] - $rec['lastgeneratedflag']) . " seconds after last generated\n";
					$changed = true;
				}
			}
		}

		return $changed;
	}
	function repoStatus($dirName, $type) {
		$rev = "";
		if($type == "svn") {
			// Running "svn info" on this:
			$cmd = $this->execCfg['svn'].' info "'.$dirName.'"';
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['info'] = implode(chr(10),$res);

			$svnInfo = $this->getSvnInfoAttributes($res);
			$date = preg_split("/\\([^\\)]+\\)$/", $svnInfo["Last Changed Date"]);
			$rev = array("rev" => $svnInfo['Last Changed Rev'], "time" => strtotime($date[0]));
		} elseif($type == "git") {
			$cmd = "cd " . $dirName . chr(10);
			//$cmd .= $this->execCfg['git'].' rev-list --all . | wc -l';
			$cmd .= $this->execCfg['git'].' log origin/master -n 1 --format=%ct .';
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['revision'] = implode(chr(10),$res);
			$rev = array("rev"=>$res[0], "time" => $res[0]);
		}
		return $rev;
	}
	function updateRec($rec, $type) {
		$log = array();
		$dirInfo = $this->getAbsDirFile($rec,TRUE);
		if(is_array($dirInfo)) {

			$rev = $this->repoStatus($dirInfo['absDir'], $type);
			$rev = $rev["rev"];
			//If last-changed-revision from SVN info doesn't match that stored in the record, we will assume that we need to regenerate the HTML and default PDF file; so we clear the lastgeneratedflag and update revision:
			if (($rev != $rec['lastchangedrevision'] && $rev != "") || $this->noteHasChanged($rec, $dirInfo['absFile'], $type))	{
				$this->clearGenerationFlag($rec['uid'], $rev);
				$log[$rec['uid']]['actions'] = 'Cleared last-generated-flag; will update HTML and PDF soon...';
				$info = array(
						"update" => true,
						"oldrev" => $rec['lastchangedrevision'],
						"newrev" => $rev,
						"log" => $log
					);
				return $info;
			}
		} else {
			$log[$rec['uid']]['echo'] = "ERROR: ".$dirInfo;
			return false;
		}
	}

	/****************************************
	 ***
	 *** SVN
	 ***
	 ***************************************/
	
	/**
	 * Updates enote from SVN and returns log-array
	 * The last-changed revision from the update is compared with that stored in the record and if the SVN version is never, the "generationflag" is cleared.
	 *
	 * @param 	array	enote record
	 * @return 	array	log array
	 */	
	function updateSVN($rec)	{
		$log = array();

		$dirInfo = $this->getAbsDirFile($rec,TRUE);

		if (is_array($dirInfo))	{

				# SVN update:
			exec("svn cleanup " . $dirInfo['absDir']);
			$cmd = $this->execCfg['svn'].' update '.$this->execCfg['svnUSERPASSoptions'].' --accept theirs-full "'.$dirInfo['absDir'].'"';
			$log[$rec['uid']]['cmd'] = $cmd;
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['res'] = implode(chr(10),$res);
			
				// Running "svn info" on this:
			$cmd = $this->execCfg['svn'].' info "'.$dirInfo['absDir'].'"';
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['info'] = implode(chr(10),$res);

			$svnInfo = $this->getSvnInfoAttributes($res);

				// If last-changed-revision from SVN info doesn't match that stored in the record, we will assume that we need to regenerate the HTML and default PDF file; so we clear the lastgeneratedflag and update revision:
			if ($svnInfo['Last Changed Rev'] > $rec['lastchangedrevision'])	{
				$this->clearGenerationFlag($rec['uid'], $svnInfo['Last Changed Rev']);
				$log[$rec['uid']]['actions'] = 'Cleared last-generated-flag; will update HTML and PDF soon...';
			}
		} else {
			$log[$rec['uid']]['echo'] = "ERROR: ".$dirInfo;
		}
		
		return $log;
	}
	
	/**
	 * Parses SVN info output to an associative array:
	 *
	 * @param 	array	SVN info result array
	 * @return 	array	Associative array with key->value pairs.
	 */	
	function getSvnInfoAttributes($res)	{
		$output = array();
		foreach($res as $key => $value)	{
			preg_match('/^([^:]*):(.*)$/', $value, $matches);
			$output[trim($matches[1])]=trim($matches[2]);
		}	
		return $output;
	}
	
	
	



	/****************************************
	 ***
	 *** GIT
	 ***
	 ***************************************/

	function updateGIT($rec) {
		echo "ERROR: GIT SUPPORT CURRENTLY NOT WORKING. AVOID USING --uid with --svnupdate !\n";
		return false;
		$log = array();

		$dirInfo = $this->getAbsDirFile($rec,TRUE);

		if(is_array($dirInfo)) {
			$cmd = "cd " . $dirInfo['absDir'] . chr(10);
			$cmd .= "git stash".chr(10). "git pull -Xtheirs" . chr(10). "git merge -Xours stash@{0}";
			$log[$rec['uid']]['cmd'] = $cmd;
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['res'] = implode(chr(10),$res);
			$cmd = "cd " . $dirInfo['absDir'] . chr(10);
			$cmd .= $this->execCfg['git'].' log origin/master -n 1 --format=%ct .';
			$res = array();
			exec($cmd,$res);
			$log[$rec['uid']]['revision'] = implode(chr(10),$res);
				//If last-changed-revision from SVN info doesn't match that stored in the record, we will assume that we need to regenerate the HTML and default PDF file; so we clear the lastgeneratedflag and update revision:
			if ($res[0] != $rec['lastchangedrevision'])	{
				$this->clearGenerationFlag($rec['uid'], $res[0]);
				$log[$rec['uid']]['actions'] = 'Cleared last-generated-flag; will update HTML and PDF soon...';
			}
		} else {
			$log[$rec['uid']]['echo'] = "ERROR: ".$dirInfo;
		}

		return $log;
	}

	function timestampDir($path) {
		$dh = opendir($path);
		$timestamp = 0;
		while($f = readdir($dh)) {
			if ($f !== ".." && $f !== "."){
				if(filemtime($path.$f) > $timestamp)
					$timestamp = filemtime($path.$f);
			}
		}
		return $timestamp;
	}
	/****************************************
	 ***
	 *** COPY to LIVE
	 ***
	 ***************************************/

	
	/**
	 * Copies files from preview area to live area.
	 * It does not copy .svn directories.
	 * It copies _HTML content too.
	 *
	 * @param 	array	enote record
	 * @return array	log
	 */	
	function copy2live($rec)	{
		$log = array();
		if((bool) array_sum(unserialize($rec['generationError']))) {
			$log['ERROR'] = "Will not copy eNote with UID " . $rec['uid'] . " to live due to faulty LaTeX code.";
			return $log;
		}
		$dirInfo = $this->getAbsDirFile($rec,TRUE);
		if (is_array($dirInfo))	{
			$directories = $this->getDirectories($dirInfo);
			if (is_array($directories))	{
				$log['direcories'] = $directories;
				
				if (!is_dir(t3lib_div::getFileAbsFileName($directories['texFromRelDir'])))	{ $log['ERROR'] = "Error: ".$directories['texFromRelDir']." was not a directory!"; return $log; }
				if (!is_dir(t3lib_div::getFileAbsFileName($directories['texToRelDir_parent'])))	{ $log['ERROR'] = "Error: ".$directories['texToRelDir_parent']." was not a directory!"; return $log; }
				if (!is_dir(t3lib_div::getFileAbsFileName($directories['htmlFromRelDir'])))	{ $log['ERROR'] = "Error: ".$directories['htmlFromRelDir']." was not a directory!"; return $log; }
				if (!is_dir(t3lib_div::getFileAbsFileName($directories['htmlToRelDir_parent'])))	{ $log['ERROR'] = "Error: ".$directories['htmlToRelDir_parent']." was not a directory!"; return $log; }

					# Rsync Tex
				$cmd = $this->execCfg['rsync'].' -av --exclude=\.svn/ "'.t3lib_div::getFileAbsFileName($directories['texFromRelDir']).'" "'.t3lib_div::getFileAbsFileName($directories['texToRelDir']).'"';
				$log['rsync_tex']['cmd'] = $cmd;
				$res = array();
				exec($cmd,$res);
				$log['rsync_tex']['res'] = implode(chr(10),$res);

					# Rsync HTML
				$cmd = $this->execCfg['rsync'].' -av "'.t3lib_div::getFileAbsFileName($directories['htmlFromRelDir']).'" "'.t3lib_div::getFileAbsFileName($directories['htmlToRelDir']).'"';
				$log['rsync_html']['cmd'] = $cmd;
				$res = array();
				exec($cmd,$res);
				$log['rsync_html']['res'] = implode(chr(10),$res);
				
					# Updates the revision number of the live enote:
				$fields_values = array(
					'lastchangedrevision_live' => $rec['lastchangedrevision'],
				);
				$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_enoteserver_note','uid='.intval($rec['uid']),$fields_values);
			}
		}
		
		return $log;
	}
	
	/**
	 * Returns to/from directories for copying from Preview to Live.
	 * ONLY works in Preview mode
	 *
	 * @param 	array	Dirinfo array for the enote, as from ->getAbsDirFile()
	 * @return 	array 	with directories, provided that we are in preview mode.
	 */	
	function getDirectories($dirInfo)	{
		$uid = $dirInfo['enoteUid'];
		if (t3lib_div::isFirstPartOfStr($dirInfo['siteRelDir'],$this->dataDir.'preview/'))	{
			$directories = array(
				'texFromRelDir' => $dirInfo['siteRelDir'],
				'texToRelDir' => $this->dataDir.'live/'.substr($dirInfo['siteRelDir'],strlen($this->dataDir.'preview/')),
				'htmlFromRelDir' => $this->dataDir.'preview/_HTML/'.$uid.'/',
				'htmlToRelDir' => $this->dataDir.'live/_HTML/'.$uid.'/',
#				'htmlToRelDir' => 'enoteHTML/'.$uid.'/'
			);
			
			$directories['htmlToRelDir_parent'] = preg_replace('/[^\/]+\/$/','',$directories['htmlToRelDir']);
			$directories['texToRelDir_parent'] = preg_replace('/[^\/]+\/$/','',$directories['texToRelDir']);
			
			return $directories;
		}
	}







	/****************************************
	 ***
	 *** UTILITY FUNCTIONS
	 ***
	 ***************************************/

	/**
	 * Based on a eNote record, it will check if the given directory and filename are valid. If so, it returns an array with absolute paths. If not, a string error message is returned.
	 *
	 * @param	array		Record of a eNote
	 * @param	boolean		If set, runs in preview mode.
	 * @return	mixed		String error message if problems, otherwise an array with validated paths.
	 */
	function getAbsDirFile($noteRecord,$preview)	{
		$result=array();
		if (!isset($preview))	die("preview is not set");

			// Fix if there is a slash in the end or not:
		$result['relDir'] = preg_replace('/\/*$/','',trim($noteRecord['directory'])).'/';
			// mode dir:
		$result['siteRelDir_mode'] = $this->dataDir.($preview?'preview':'live').'/';
		
			// Directory relative to installation:
		$result['siteRelDir'] = $result['siteRelDir_mode'].$result['relDir'];
		
			// Absolute path:
		$result['absDir'] = t3lib_div::getFileAbsFileName($result['siteRelDir']);
		if (@is_dir($result['absDir']))	{
			$result['relFile'] = trim($noteRecord['texfile']);
			$result['absFile'] = $result['absDir'].$result['relFile'];
			if (@is_file($result['absFile']))	{
				// Do nothing, all is fine.
			} else {	return 'Error: File "'.$result['relDir'].$result['relFile'].'" not found.';	}
		} else {	return 'Error: Directory "'.$result['relDir'].'" not found.';	}
	
			// Set uid as well:
		$result['enoteUid'] = $noteRecord['uid'];
	
		return $result;
	}
	
	/**
	 * 
	 *
	 * @param 
	 * @return
	 */	
	function setBookConfiguration($bookRec)	{
			// Set book-dir:
		$this->bookdir = preg_replace('/\/$/','',$bookRec['bookdir']);

		if (!@is_dir(t3lib_div::getFileAbsFileName($this->dataDir.'books/'.$this->bookdir)))	{
			$this->bookdir = FALSE;
		}
		
			// Set encoding:
		$this->bookEncoding = $this->encodingMap[$bookRec['encoding']];
		
		$flexformArray = t3lib_div::xml2array($bookRec['flexform']);
		if (is_array($flexformArray))	{

				// Box env:
			if (is_array($flexformArray['data']['sDEF']['lDEF']['boxenv_cfg']['el']))	{
				$this->LaTeX_boxEnvironments = array();
				foreach($flexformArray['data']['sDEF']['lDEF']['boxenv_cfg']['el'] as $el)	{
					if (trim($el['field_boxenv']['el']['field_key']['vDEF']))	{
						$this->LaTeX_boxEnvironments[$el['field_boxenv']['el']['field_key']['vDEF']] = array(
								'title' => $el['field_boxenv']['el']['field_title']['vDEF'], 
								'PDFExclAlt' => trim($el['field_boxenv']['el']['field_PDFExclAlt']['vDEF'])
						);
					}
				}
			}

				// Div Cmd:
			if (is_array($flexformArray['data']['sDEF']['lDEF']['divcmd_cfg']['el']))	{
				$this->LaTeX_divCmdEnvironments = array();
				foreach($flexformArray['data']['sDEF']['lDEF']['divcmd_cfg']['el'] as $el)	{
					if (trim($el['field_divcmd']['el']['field_key']['vDEF']))	{
						$this->LaTeX_divCmdEnvironments[$el['field_divcmd']['el']['field_key']['vDEF']] = array(
								'title' => $el['field_divcmd']['el']['field_title']['vDEF']
						);
					}
				}
			}

				// Notice env:
			if (is_array($flexformArray['data']['sDEF']['lDEF']['noticeenv_cfg']['el']))	{
				$this->LaTeX_noticeEnrironments = array();
				foreach($flexformArray['data']['sDEF']['lDEF']['noticeenv_cfg']['el'] as $el)	{
					$this->LaTeX_noticeEnrironments[$el['field_boxenv']['el']['field_key']['vDEF']] = array();
				}
			}
			
				// Generally
			$this->bookConfiguration = $flexformArray['data']['sDEF']['lDEF'];
		} else return $flexformArray;
	}
	
	function loadBookConfiguration($enoteUid)	{
		$eNoteRec = $this->getEnoteRecord($enoteUid);
		return $this->setBookConfiguration($this->getBookRecord($eNoteRec['book']));
	}
	
	/**
	 * Pass the content through tidy - a little program that cleans up HTML-code.
	 * TODO: ENCODING
	 *
	 * @param	string		The page content to clean up. Will be written to a temporary file which "tidy" is then asked to clean up. File content is read back and returned.
	 * @return	string		Returns the
	 */
	function tidyHTML($content,$charset,$all=FALSE)		{
		$oldContent = $content;
		$fname = t3lib_div::tempnam('typo3_tidydoc_');		// Create temporary name
		@unlink ($fname);	// Delete if exists, just to be safe.
		$fp = fopen ($fname,'wb');	// Open for writing
		fputs ($fp, $content);	// Put $content
		@fclose ($fp);	// Close

		@exec($this->execCfg['tidy'].' -i -quiet -asxhtml -numeric -'.$charset.' '.$fname . " 2>/dev/null", $output);			// run the $content through 'tidy', which formats the HTML to nice code.
		@unlink ($fname);	// Delete the tempfile again
		$content = implode(chr(10),$output);
		if (!trim($content))	{
			$content = $oldContent;	// Restore old content due empty return value.
			debug('"tidy" returned an empty value!');
		}
		
		if (!$all)	{
			preg_match('/\<body[^>]*\>(.*)<\/body>/ism' ,$content , $matches);
			$content = $matches[1];
		}
		return $content;
	}
		
	/**
	 * Gets enote-record from UID
	 */
	function getEnoteRecord($uid)	{
		if (is_object($this->piObj))	{
			return $this->piObj->pi_getRecord('tx_enoteserver_note',$uid);
		} else {
			return t3lib_BEfunc::getRecord('tx_enoteserver_note',$uid);
		}
	}
	
	/**
	 * Gets book record from UID
	 */	
	function getBookRecord($uid)	{
		if (is_object($this->piObj))	{
			return $this->piObj->pi_getRecord('tx_enoteserver_book',$uid);
		} else {
			return t3lib_BEfunc::getRecord('tx_enoteserver_book',$uid);
		}
	}
	
	/**
	 * Clear the "lastgeneratedflag" to zero - signals, that HTML and default PDF should be regenerated. Also updates the revision number.
	 *
	 * @param 
	 * @return
	 */	
	function clearGenerationFlag($uid,$newRevision)	{
		$fields_values = array(
			'lastchangedrevision' => $newRevision,
			'lastgeneratedflag' => 0
		);
		$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_enoteserver_note','uid='.intval($uid),$fields_values);
	}
	
	/**
	 * Sets the lastgeneratedflag to timestamp (shows the record has been processed to HTML and default PDF)
	 *
	 * @param 
	 * @return
	 */	
	function setGenerationFlag($uid)	{
		$fields_values = array(
			'lastgeneratedflag' => time()
		);
		$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_enoteserver_note','uid='.intval($uid),$fields_values);
	}
}

?>